import { Request, Response, NextFunction } from 'express';
import JwtUtil from '@/utils/security/jwt.util';
import ApiResponse from '@/utils/api/api-response.util';
import { AuthRequest } from '@/types';
import { getLogger } from '@/utils/logger';
import { ONLINE_USER_KEY_PREFIX, getUuidByJwt } from '@/services/monitor/user-online.service';
import cacheUtils from '@/utils/cache/cache.util';
import redisClient from "@/config/redis";

// 创建日志记录器
const logger = getLogger('auth-middleware');

// 不记录认证警告的路径列表
const noAuthWarningPaths = ['/monitor/server'];

/**
 * JWT认证中间件
 * 用于验证用户是否已登录，解析令牌中的用户信息
 */
export const authMiddleware = async (req: AuthRequest, res: Response, next: NextFunction): Promise<Response | void> => {
  // 获取请求头中的Authorization字段
  const authHeader = req.headers.authorization;
  if (!authHeader) {
    // 对特定路径不记录警告日志
    if (!noAuthWarningPaths.some(path => req.path.includes(path))) {
      logger.warn('未提供认证令牌', { path: req.path });
    }
    return ApiResponse.error(res, '未提供认证令牌', 401);
  }

  // 检查Authorization格式
  const parts = authHeader.split(' ');
  if (parts.length !== 2 || parts[0] !== 'Bearer') {
    logger.warn('认证令牌格式错误', { path: req.path, authHeader });
    return ApiResponse.error(res, '认证令牌格式错误', 401);
  }

  const token = parts[1];
  logger.info('收到令牌验证请求' +  JSON.stringify({ path: req.path, token: token.substring(0, 20) + '...' }));

  // 验证令牌
  const decodedUser = JwtUtil.verifyToken(token);
  if (!decodedUser) {
    // 令牌无效
    logger.warn('无效的认证令牌', { path: req.path });
    return ApiResponse.error(res, '无效的认证令牌', 401);
  }

  // 检查令牌是否过期
  if (JwtUtil.isTokenExpired(token)) {
    logger.warn('认证令牌已过期', { path: req.path, userId: decodedUser.userId });
    return ApiResponse.error(res, '认证令牌已过期，请重新登录', 401);
  }

  // 新增：强制下线校验，token必须在Redis在线用户缓存中
  // 对/logout接口放行强制下线校验，保证与Java后端一致
  if (req.path === '/logout') {
    req.user = decodedUser;
    logger.info('登出接口放行', { path: req.path, userId: decodedUser.userId });
    return next();
  }

  // 通过jwt查uuid
  const uuid = await getUuidByJwt(token);
  
  if (!uuid) {
    logger.warn('未找到jwt-uuid映射，认证令牌已失效', { path: req.path, userId: decodedUser.userId });
    return ApiResponse.error(res, '登录状态已失效，请重新登录', 401);
  }
  // 再查uuid对应的在线用户缓存
  const cacheResult = await cacheUtils.get(`${ONLINE_USER_KEY_PREFIX}:${uuid}`);
  let data = await redisClient.get(`${ONLINE_USER_KEY_PREFIX}:${uuid}`);
  if (!cacheResult.success) {
    logger.warn('认证令牌已被强制下线', { path: req.path, userId: decodedUser.userId });
    return ApiResponse.error(res, '登录状态已失效，请重新登录', 401);
  }

  // 将用户信息添加到请求对象中
  req.user = decodedUser;
  logger.info('令牌验证成功' + JSON.stringify({ path: req.path, userId: decodedUser.userId, roles: decodedUser.roles }));
  next();
  return;
};

/**
 * 可选的认证中间件
 * 不强制要求用户登录，但如果有令牌，会解析用户信息
 */
export const optionalAuthMiddleware = (req: AuthRequest, res: Response, next: NextFunction): void => {
  // 获取请求头中的Authorization字段
  const authHeader = req.headers.authorization;
  if (!authHeader) {
    // 没有令牌，继续处理请求
    next();
    return;
  }

  // 检查Authorization格式
  const parts = authHeader.split(' ');
  if (parts.length !== 2 || parts[0] !== 'Bearer') {
    // 格式错误，继续处理请求
    next();
    return;
  }

  const token = parts[1];

  // 验证令牌
  const decodedUser = JwtUtil.verifyToken(token);
  if (decodedUser && !JwtUtil.isTokenExpired(token)) {
    // 令牌有效，添加用户信息
    req.user = decodedUser;
  }

  next();
};

/**
 * 角色验证中间件
 * @param roles 允许访问的角色列表
 */
export const roleMiddleware = (roles: string[]) => {
  return (req: AuthRequest, res: Response, next: NextFunction): Response | void => {
    if (!req.user) {
      return ApiResponse.error(res, '未提供认证令牌', 401);
    }

    // 检查用户是否有所需角色
    const userRoles = req.user.roles || [];
    const hasRequiredRole = roles.some(role => userRoles.includes(role));

    if (!hasRequiredRole) {
      return ApiResponse.error(res, '权限不足，需要特定角色', 403);
    }

    next();
    return;
  };
};

/**
 * 权限验证中间件
 * @param permission 需要的权限标识
 */
export const permissionMiddleware = (permission: string) => {
  return (req: AuthRequest, res: Response, next: NextFunction): Response | void => {
    if (!req.user) {
      return ApiResponse.error(res, '未提供认证令牌', 401);
    }

    // 管理员拥有所有权限
    if (req.user.permissions.includes('*')) {
      next();
      return;
    }

    // 检查用户是否有所需权限
    const userPermissions = req.user.permissions || [];
    const hasPermission = userPermissions.includes(permission);

    if (!hasPermission) {
      return ApiResponse.error(res, '权限不足，需要特定操作权限', 403);
    }

    next();
    return;
  };
};